package com.siteseat.common.deploy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;

import com.siteseat.common.exception.InternalException;
import com.siteseat.common.foundation.PropertyHelper;
import com.siteseat.common.json.JacksonMapper;
import com.siteseat.common.security.Credential;
import com.siteseat.common.security.SecureComponent;
import com.siteseat.common.security.SecurityException;

/**
 * 
 *
 * @author yqiang
 * Success Factors
 */
public abstract class AbstractDeployRepository extends SecureComponent implements DeployRepository {

  private final Map<String, DeployEntry> entries = new HashMap<String, DeployEntry>();

  private Credential actor;
  
  /**
   * Gets the actor
   *
   * @return the actor
   */
  public Credential getActor() {
    return actor;
  }
  
  /**
   * 
   *
   * @return
   */
  public String getActorName() {
    return getActor().getName();
  }

  /**
   * Sets the actor
   *
   * @param actor the actor to set
   */
  public void setActor( Credential actor ) {
    this.actor = actor;
  }

  /**
   * 
   *
   * @param entry
   * @return
   */
  protected abstract void doDeploy( DeployEntry entry ) throws SecurityException;

  /**
   * 
   *
   * @param entry
   * @return
   */
  protected void doRedeploy(DeployEntry entry)  throws SecurityException{
    doUndeploy( entry );    
    doDeploy( entry );
  }


  /**
   * 
   *
   * @param entry
   */
  protected abstract void doUndeploy( DeployEntry entry ) throws SecurityException;
  
  
  /**
   * {@inheritDoc}
   */
  @Override
  public Map<String, DeployEntry> getEntries() {
    return Collections.unmodifiableMap( _getEntries() );
  }
  

  /**
   * 
   *
   * @return
   */
  protected Map<String, DeployEntry> _getEntries() {
    return this.entries;
  }
  

  /**
   * {@inheritDoc}
   */
  @Override
  public void deploy( DeployEntry entry )  throws SecurityException {    
    doDeploy( entry );
    _getEntries().put( entry.getFilePath(), entry );
  }
  
  

  /**
   * {@inheritDoc}
   */
  @Override
  public void redeploy( DeployEntry entry )  throws SecurityException {
    undeploy( entry );
    deploy( entry );
  }
  

  /**
   * {@inheritDoc}
   */
  @Override
  public void undeploy( DeployEntry entry ) throws SecurityException {
    log.info( "undeploying " + entry.getFilePath() );
    
    Map<String, DeployEntry> es = _getEntries();
    String filePath = entry.getFilePath();
    
    try {
      doUndeploy( entry );
      es.remove( filePath );
      log.info( "undeployed " + entry.getFilePath() );
    } catch( Exception e ) {
      log.error( "Error undeploying " + filePath, e );
      es.remove( filePath );
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected void doDestroy() throws Exception {
    // TODO Auto-generated method stub
    
  }
  

  /**
   * {@inheritDoc}
   */
  @Override
  protected void doInit() throws Exception {

    PropertyHelper.ensureNotNull( log, getActor(), "actor" );
    if( getActor().isAdministrator() == false ) {
      throw new InternalException( "Actor <" + actor.getName() + " is not an administrator" );
    }
  }
  
  /**
   * 
   *
   * @param file
   * @return
   */
  public <T> T parseEntityFromJsonFile( File f, Class<T> entityType ) {
    log.info( "Loading " + entityType.getName() + " file <" + f.getAbsolutePath() + ">" );
    
    FileInputStream fis;
    try {
      fis = new FileInputStream( f );
    } catch (FileNotFoundException e) {
      throw new InternalException(e);
    }

    T result;
    try {
      result = JacksonMapper.MAPPER.readValue( fis, entityType );
    } catch (IOException e) {
      throw new InternalException(e);
    } finally {
      IOUtils.closeQuietly(fis);
    }
    
    return result;
  }
  
}
